/**
 * File: BucketReadInfo.java
 * Created by: mhaimel
 * Created on: Nov 30, 2010
 * CVS:  $Id: BucketReadInfo.java 1.0 Nov 30, 2010 4:00:56 PM mhaimel Exp $
 */
package uk.ac.ebi.curtain.processor.general;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.util.Properties;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import uk.ac.ebi.curtain.utils.CurtainUncheckedException;
import uk.ac.ebi.curtain.utils.io.impl.FileIO;

/**
 * @author mhaimel
 *
 */
public class BucketReadInfo {
	private static final String MEDIAN_BP_COVERAGE = "medianBpCoverage";
	private static final String WEIGHTED_MEAN_COVERAGE = "weightedMeanCoverage";
	private static final String BP_READS = "bpReads";
	private static final String BP_CTGS = "bpContigs";
	private static final String NUMBER_OF_READS = "numberOfReads";
	private static final Log LOG = LogFactory.getLog(BucketReadInfo.class);
	private static final String AVG_READ_LENGTH = "avgReadLength";
	private final Long bucketId;
	private final Integer category;
	private Integer avgReadLength;
	private Long numberOfReads;
	private Long bpReads;
	private Long bpContigs;
	private Double medianBpCoverage;
	private Double weightedMeanCoverage;
	
	public static void main(String[] args) {
		BucketReadInfo b = BucketReadInfo.fromFile(1l, 1, new File("/scratch/wheat/perfect/_300_600/curtain/curtain_1/bucket_coll/00/00/00/01/info_1.txt"));
		System.out.println(b);
	}
	
	public BucketReadInfo(Long bucketId, Integer category) {
		this.bucketId = bucketId;
		this.category = category;
	}
	
	public void toFile(File file){
		toFile(file,false);
	}
	
	public void toFile(File file, boolean b) {
		Writer out = null;
		try {
			out = new FileIO(file,b).getWriter();
			persist(out);
		} catch (IOException e) {
			throw new CurtainUncheckedException("Problems writing properties to file: " + file);
		}finally{
			FileIO.closeQuietly(out);
		}
	}
	
	public void persist(Writer out) throws IOException {
		Properties prop = new Properties();
		addPropery(prop,AVG_READ_LENGTH, getAvgReadLength());
		addPropery(prop,NUMBER_OF_READS, getNumberOfReads());	
		addPropery(prop,BP_READS, getBpReads());		
		addPropery(prop,BP_CTGS, getBpContigs());		
		addPropery(prop,MEDIAN_BP_COVERAGE, getMedianBpCoverage());	
		addPropery(prop,WEIGHTED_MEAN_COVERAGE, getWeightedMeanCoverage());	
		prop.store(out , "");
	}
	
	/**
	 * 
	 * @param bucketId
	 * @param category
	 * @param f
	 * @return BucketReadInfo Null if file does not exist
	 */
	public static BucketReadInfo fromFile(Long bucketId, Integer category,File f){
		if(!f.exists() || f.length() == 0){
			return null;
		}
		Properties prop = new Properties();
		InputStream in = null;
		try {
			in = new FileIO(f).getInputStream();
			prop.load(in);
		} catch (IOException e) {
			throw new CurtainUncheckedException("Problems reading properties from file: " + f);
		} finally{
			FileIO.closeQuietly(in);
		}
		BucketReadInfo info = fromProperties(bucketId, category, prop);
		return info;
	}

	private static BucketReadInfo fromProperties(Long bucketId, Integer category,
			Properties prop) {
		BucketReadInfo info = new BucketReadInfo(bucketId, category);
		String res = prop.getProperty(AVG_READ_LENGTH, null);
		if(null != res){
			info.setAvgReadLength(Integer.valueOf(res));			
		}
		res = prop.getProperty(NUMBER_OF_READS, null);
		if(null != res){
			info.setNumberOfReads(Long.valueOf(res));			
		}
		res = prop.getProperty(BP_READS, null);
		if(null != res){
			info.setBpReads(Long.valueOf(res));			
		}
		res = prop.getProperty(BP_CTGS, null);
		if(null != res){
			info.setBpContigs(Long.valueOf(res));			
		}
		res = prop.getProperty(MEDIAN_BP_COVERAGE, null);
		if(null != res){
			info.setMedianBpCoverage(Double.valueOf(res));			
		}
		res = prop.getProperty(WEIGHTED_MEAN_COVERAGE, null);
		if(null != res){
			info.setWeightedMeanCoverage(Double.valueOf(res));			
		}
		return info;
	}
	
	private boolean addPropery(Properties prop,String id,Object o){
		if(o == null){
			return false;
		} else {
			prop.put(id, o.toString());	
			return true;
		}
	}
	
	public Long getBpContigs() {
		return bpContigs;
	}
	
	public void setBpContigs(Long bpContigs) {
		this.bpContigs = bpContigs;
	}
	
	public Long getBpReads() {
		return bpReads;
	}
	public void setBpReads(Long bpReads) {
		this.bpReads = bpReads;
	}
	
	public Long getNumberOfReads() {
		return numberOfReads;
	}
	public void setNumberOfReads(Long numberOfReads) {
		this.numberOfReads = numberOfReads;
	}
	
	public Integer getAvgReadLength() {
		return avgReadLength;
	}
	public void setAvgReadLength(Integer avgReadLength) {
		this.avgReadLength = avgReadLength;
	}

	public Long getBucketId() {
		return bucketId;
	}
	public Integer getCategory() {
		return category;
	}
	
	public Double getMedianBpCoverage() {
		return medianBpCoverage;
	}
	
	public void setMedianBpCoverage(Double medianBpCoverage) {
		this.medianBpCoverage = medianBpCoverage;
	}
	
	/**
	 * @return the weightedMeanCoverage
	 */
	public Double getWeightedMeanCoverage() {
		return weightedMeanCoverage;
	}

	/**
	 * @param weightedMeanCoverage the weightedMeanCoverage to set
	 */
	public void setWeightedMeanCoverage(Double weightedMeanCoverage) {
		this.weightedMeanCoverage = weightedMeanCoverage;
	}

	public boolean canCalculateBpCoverage(){
		return this.getBpContigs()!= null && this.getBpReads()!=null;
	}
	
	public boolean canCalculateKmerCoverage(){
		return this.getAvgReadLength()!= null && canCalculateBpCoverage();
	}
	
//	public double calculateKmerCoverage(int kmer){
//		if(!canCalculateKmerCoverage()){
//			throw new CurtainUncheckedException("Not all values available!!! " + this);
//		}
//		if(getAvgReadLength()==0){
//			throw new CurtainUncheckedException("ReadLength should NOT be 0!!! " + this);
//		}
//		return calculateKmerCoverage(kmer,calculateBpCoverage(),getAvgReadLength()); 
////		calculateBpCoverage()*(getAvgReadLength()-kmer+1)/getAvgReadLength();
//	}
	
	public static double calculateKmerCoverage(int kmer, double bpCoverage, int readLength ){
		return bpCoverage*(readLength-kmer+1)/readLength;
	}
	
	public double calculateBpCoverage(){
		if(!canCalculateBpCoverage()){
			throw new CurtainUncheckedException("Not all values available!!! " + this);
		}
		if(getBpContigs()== 0){
			throw new CurtainUncheckedException("Contig bp count should NOT be 0!!! " + this);
		}
		return getBpReads()/getBpContigs();
	}
	
	@Override
	public String toString() {
		return ToStringBuilder.reflectionToString(this,ToStringStyle.SHORT_PREFIX_STYLE);
	}
}
